home *** CD-ROM | disk | FTP | other *** search
- /* Expire old messages.
- * Inspired by 'expire.c' by Bernie Roehl.
- * Substantially rewritten for integration into KA9Q NOS,
- * WG7J v1.01 and later
- * by Johan. K. Reinalda, WG7J/PA3DIS, March/April 92
- *
- * Old bid expiry by WG7J, March 92
- * Index file support for jnos 1.10x3 and later added. WG7J Summer 1993
- */
- /* 'expire #' sets the expire interval for n hours.
- * Each time the timer goes off, a new process is started,
- * that expires the old messages...
- *
- * The control file '~/spool/expire.dat' contains lists of
- * filename age
- * where 'filename' is the name of the .txt file under '~/spool/mail'
- * containing the messages (without the .txt extension) and where
- * age = maximum age of message in days.
- *
- * If no age is given, the default age is 21 days.
- *
- * filename can be extended into subdirectories, and can have either
- * '/', '\' or '.' to indicate subdirectories.
- * filename should NOT have the ending '.txt'
- */
-
- /* 25 March 1994
- * Expire now expires messages stored in the NNTP server format.
- * the additions to expire.dat 'sort of' follow the conventions for nntp
- * in other areas of nos, namely the delimiter for nntp groups is bang (!)
- * thus the format for expiring news items is
- * !<newsgroup-name> age for example !ampr.vk5 21
- * age still defaults to 21 days if not specified.
- * automatic active and history file updates are done on each firing of
- * the expiry process, only if at least one newsgroup was processed.
- * all records are treated the same in the history file, and are expired
- * when older than the largest number of days specified for any newsgroup.
- * numbers of expiries in groups and history are both logged if > 0
- * if you have any ideas on the above, dont keep them to yourself !! ;-)
- * this code is not rigorously tested :-) vk5xxx march 1994
- *
- * April 7 1994
- * added test for articles to ensure they are numeric. nos uses other control
- * files in the newsgroup area (namely news.rc), nntp_expire would expire
- * these happily, and update_nntp_active wqas confused by them (start = 0)
- *
- * June 25 1994
- * Update the news.rc file with the lowest article number when the news.rc
- * number is invalid.
- */
-
- #ifdef MSDOS
- #include <dir.h>
- #include <dos.h>
- #endif
- #include <alloc.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <sys/timeb.h>
- #include <ctype.h>
- #include <time.h>
- #include "global.h"
- #include "timer.h"
- #include "proc.h"
- #include "bm.h"
- #include "files.h"
- #include "smtp.h"
- #include "socket.h"
- #include "index.h"
- #ifdef NNTPS
- #include "dirutil.h" /* NNTP expire */
- #include <limits.h> /* NNTP expire */
- #endif
-
- #ifdef LINUX
- extern int unlink __ARGS((char *));
- #endif
-
- #ifndef __BORLANDC__
- #ifndef UNIX
- time_t mktime(struct tm *);
-
- /* If you're using BC++ 2.0 or higher, you don't need this,
- * but TCC 2.0 doesn't have it... (But, TC++ v1.01 does)
- */
- /* Simple emulation of the mktime() call (sort-of works :-) )
- * doesn't do any error checking,
- * no timezone adjustments or value adjustments
- * Simply 'sort-a' calculates the number of seconds since 1970 - WG7J
- */
- time_t
- mktime(t)
- struct tm *t;
- {
- static int total[12]={0,31,59,90,120,151,181,212,243,273,304,334};
- int years;
- int leapyears;
- int days;
-
- /* time count start at jan 1, 1970, 00:00 hrs */
- years = t->tm_year - 70;
- /* adjust for leap-years */
- leapyears = (years + 2) / 4;
- if (!((years+70) & 3) && (t->tm_mon < 2))
- --leapyears; /* no extra day until 3/1 or after */
-
- days = years*365L + leapyears + total[t->tm_mon] + (t->tm_mday-1);
-
- return( days*86400L + t->tm_hour*3600L + t->tm_min*60L + t->tm_sec);
- }
- #endif /* UNIX */
- #endif /* __BORLANDC__ */
-
- /* Include the rest in #ifdef's, so we don't pull in the whole module
- * when we only have AT defined and NOT EXPIRE !
- * (since these are the two modules that needs the surrogate mktime()
- * if compiling with Turbo C 2.0 )
- */
- #ifdef EXPIRY
-
- /* Default expiry values: */
- #define DEFAULT_AGE 21 /* 21 days from origination date */
- #define MSPHOUR (1000L*60L*60L)
- static struct timer Expiretimer;
- static int Eproc;
-
- static void Expireprocess __ARGS((int a,void *v1,void *v2));
- static void Expiretick __ARGS((void *));
- static void expire __ARGS((char *,int));
- static void Oldbidtick __ARGS((void *p));
-
- #ifdef NNTPS /* for NNTP expiry */
- /* NNTP Expire stuff */
- static void expire_nntp __ARGS((char *, int));
- static void update_nntp_history __ARGS((int));
- static void update_nntp_active __ARGS((void));
- static void update_newsrc __ARGS((int, int, char *));
- static int convert_num __ARGS((char **));
- static char *newsgroup_to_path __ARGS((char *));
- #endif
-
- int
- doexpire(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- if(argc < 2) {
- tprintf("timer: %lu/%lu hrs\n",
- read_timer(&Expiretimer)/MSPHOUR,
- dur_timer(&Expiretimer)/MSPHOUR);
- return 0;
- }
- if(*argv[1] == 'n') {
- Expiretick(NULL);
- return 0;
- }
- /* set the timer */
- stop_timer(&Expiretimer); /* Just in case */
- Expiretimer.func = (void (*)())Expiretick;/* what to call on timeout */
- Expiretimer.arg = NULL; /* dummy value */
- set_timer(&Expiretimer,atol(argv[1])*MSPHOUR); /* set timer duration */
- start_timer(&Expiretimer);
- return 0;
- }
-
- void
- Expiretick(p)
- void *p;
- {
- start_timer(&Expiretimer);
- /* Spawn off the process */
- if(!Eproc)
- newproc("Expiry", 1536, Expireprocess, 0, NULL, NULL, 0);
- }
-
- static void
- Expireprocess(a,v1,v2)
- int a;
- void *v1, *v2;
- {
- char line[80];
-
- #ifdef NNTPS /* for NNTP expiry */
- int expire_nntp_history = 0;
- #endif
- int age;
- char *cp;
- FILE *ctl;
-
- Eproc = 1;
- if ((ctl = fopen(Expirefile, "r")) == NULLFILE) {
- Eproc = 0;
- return;
- }
- /* read lines from the control file */
- while(fgets(line, sizeof(line), ctl) != NULLCHAR) {
- pwait(NULL); /* be nice */
- #ifdef NNTPS /* for NNTP expiry */
- if((*line == '#') || (*line == '\n')) /* comment or blank line */
- #endif
- #ifndef NNTPS /* for NNTP expiry */
- if((*line == '#') || (*line == '!') || (*line == '\n')) /* comment or blank line */
- #endif
- continue;
- rip(line);
- /* terminate area name */
- age = DEFAULT_AGE;
- if((cp=strchr(line, ' ')) != NULLCHAR) {
- /* there is age info */
- *cp++ = '\0';
- age = atoi(cp);
- }
- pwait(NULL); /* be nice */
- #ifdef NNTPS /* for NNTP expiry */
- if (*line == '!') /* Expire NNTP entry if line begins with ! */ {
- expire_nntp(&line[1], age);
- if (expire_nntp_history < age)
- expire_nntp_history = age;
- }
- else
- #endif
- expire(line, age);
- }
- fclose(ctl);
- #ifdef NNTPS /* for NNTP expiry */
- if (expire_nntp_history) {
- update_nntp_history(expire_nntp_history);
- update_nntp_active(); /* and news.rc */
- }
- #endif
- Eproc = 0;
- }
-
- #ifdef NNTPS /* for NNTP expiry */
- /*
- expire nntp articles - the kludgomatic version.
- these routines probably arent memory friendly, but they work.
- more work needs to be done to make it meld more nicely into nos.
- coded by brett england (future amateur) and rob vk5xxx.
- */
- static
- int
- convert_num( p )
- char **p;
- {
- int i;
- char *pp = *p;
-
- i = (*pp - '0') * 10 + *(pp+1) - '0';
- (*p)+=2;
- return (i);
- }
-
- static
- void
- update_nntp_history(age)
- int age;
- {
- FILE *old, *new;
- char bckfile[FILE_PATH_SIZE];
- char line[LINELEN];
- char *p;
- struct tm tm_time;
- time_t expire_time, file_time, now;
- int history_records_expired = 0;
-
- while(mlock(Newsdir,"history"))
- pause(10000L);
-
-
- expire_time = (long)age * 24L * 60L * 60L; /* days to seconds */
- time(&now);
-
- /* Rename the history file, and use it to expire messages
- */
- sprintf(bckfile,"%s.bak",History);
- unlink(bckfile);
- if(rename(History,bckfile) == -1) {
- log(-1,"NNTP Expire History: Can't rename %s to %s",History, bckfile);
- return;
- }
-
- if((old = fopen(bckfile,"rt")) == NULL) {
- log(-1,"NNTP Expire History: Can't open file %s for read", bckfile);
- return;
- }
-
- if((new = fopen(History,"wt")) == NULL) {
- log(-1,"NNTP Expire History: Can't open file %s for write",History);
- return;
- }
-
- for(;;) {
- if(fgets(line, LINELEN, old) == NULL)
- break;
-
- p = line;
- while (*p != '\0' && *p != '>')
- p++;
- if (*p != '>') /* Some sort of corrupt line */
- continue;
- p+=2;
- tm_time.tm_year = convert_num(&p);
- tm_time.tm_mon = convert_num(&p)-1;
- tm_time.tm_mday = convert_num(&p);
- p++; /* Point to time component */
- tm_time.tm_hour = convert_num(&p);
- tm_time.tm_min = convert_num(&p);
- tm_time.tm_sec = 0;
-
- file_time = mktime(&tm_time);
-
- if (file_time > ( now - expire_time ))
- fputs(line, new);
- else
- history_records_expired++;
- }
-
- fclose(new);
- fclose(old);
- rmlock(Newsdir,"history");
-
- if(history_records_expired > 0)
- log(-1,"NNTP History: Expired %d records ...", history_records_expired);
- }
-
- /* Check the news.rc file if the number contained is less than min
- replace the news.rc file contents with min.
- */
- static
- void
- update_newsrc( min, max, path )
- int min, max;
- char *path;
- {
- FILE *newsrcfd;
- char news_file[FILE_PATH_SIZE], line[LINELEN];
- int no;
-
- sprintf(news_file,"%s/news.rc",path);
- if((newsrcfd = fopen(news_file,"rt")) == NULL) {
- log(-1,"NNTP News: Can't open file %s for read", news_file);
- return;
- }
-
- fgets(line, LINELEN, newsrcfd);
- fclose(newsrcfd);
-
- no = atoi(line);
- if((no < min) || (no > max)) {
- if((newsrcfd = fopen(news_file,"wt")) == NULL) {
- log(-1,"NNTP News: Can't open file %s for write", news_file);
- return;
- }
- fprintf(newsrcfd,"%d",min);
- fclose(newsrcfd);
- }
- }
-
- /* Update the active file and return the lowest news article
- */
- static
- void
- update_nntp_active() {
- FILE *old, *new;
- char bckfile[FILE_PATH_SIZE];
- char line[LINELEN];
- char *p, *path, *rpath;
- int min, max;
- int command, file_num;
- struct ffblk *file;
-
- /* Rename the active file
- */
- sprintf(bckfile,"%s.bak",Active);
- unlink(bckfile);
- if(rename(Active,bckfile) == -1) {
- log(-1,"NNTP Active: Can't rename %s to %s",Active, bckfile);
- return;
- }
-
- if((old = fopen(bckfile,"rt")) == NULL) {
- log(-1,"NNTP Active: Can't open file %s for read", bckfile);
- return;
- }
-
- if((new = fopen(Active,"wt")) == NULL) {
- log(-1,"NNTP Active: Can't open file %s for write",Active);
- return;
- }
-
- file = (struct ffblk *)mallocw(sizeof(struct ffblk));
- for(;;) {
- if(fgets(line, LINELEN, old) == NULL)
- break;
-
- p = line;
- while (*p != '\0' && ! isspace(*p))
- p++;
- if (*p == '\0')
- continue;
- *p = '\0';
-
- p++;
- while(*p != '\0' && (isspace(*p) || isdigit(*p)))
- p++;
-
- rpath = newsgroup_to_path( line );
- path = wildcardize(rpath);
-
- command = 0;
- min = INT_MAX;
- max = INT_MIN;
- for(;;) {
- if (!nextname(command, path, file))
- break;
- command = 1; /* Find next */
-
- if (file->ff_name[0] == '.')
- continue; /* ignore . and .. */
-
- file_num = atoi(file->ff_name);
- if (file_num > 0) { /* should always be greater than 0 */
- if (file_num < min)
- min = file_num;
- if (file_num > max)
- max = file_num;
- }
- }
- if (min == INT_MAX && max == INT_MIN) { /* No files */
- min = 1;
- max = 0;
- }
- update_newsrc(min, max, rpath);
-
- fprintf(new,"%s %05d %05d %s", line, max, min, p);
- }
- fclose(new);
- fclose(old);
- free(file);
- }
-
- static
- char
- *newsgroup_to_path( group )
- char *group;
- {
- FILE *f;
- static char line[LINELEN];
- char *cp;
-
- if((f = fopen(Pointer,"r")) == NULL)
- return((char *)NULL);
-
- for (;;) {
- if (fgets(line,LINELEN,f) == NULL)
- break;
-
- if (strcspn(line," ") != strlen(group))
- continue;
-
- if (strnicmp(group,line,strlen(group)) == 0) {
- cp = (strchr(line,' ')) + 1;
-
- rip(cp);
- fclose(f);
- return (cp);
- }
- }
- fclose(f);
- return (NULL);
- }
-
- void
- expire_nntp(nntp_name, age)
- char *nntp_name;
- int age;
- {
- char *path;
- int command = 0;
- struct ffblk file;
- struct tm tm_time;
- time_t file_time, expire_time, now;
- char nntp_file[FILE_PATH_SIZE];
- char save_path[FILE_PATH_SIZE];
- int file_num, expired = 0;
-
- /* Resolve nntp name into directory path */
- if ((path = newsgroup_to_path( nntp_name )) == NULL)
- return;
-
- expire_time = (long)age * 24L * 60L * 60L;
- time(&now);
- strcpy(save_path, path);
- path = wildcardize(path);
-
- for(;;) {
- if (!nextname(command, path, &file))
- break;
- command = 1; /* Find next */
-
- if (file.ff_name[0] == '.')
- continue; /* ignore . and .. */
-
- file_num = atoi(file.ff_name);
- /* should always be greater than 0 for a valid nntp article */
- if (file_num > 0) {
- /* only expire a file that is numeric :-) */
- tm_time.tm_sec = 0; /* DOS doesn't store this */
- tm_time.tm_min = (file.ff_ftime >> 5) & 0x3f;
- tm_time.tm_hour = (file.ff_ftime >> 11) & 0x1f;
- tm_time.tm_mday = file.ff_fdate & 0x1f;
- tm_time.tm_mon = ((file.ff_fdate >> 5) & 0xf)-1;
- tm_time.tm_year = (file.ff_fdate >> 9) + 80;
-
- file_time = mktime(&tm_time);
-
- if (( now - expire_time ) > file_time) {
- sprintf(nntp_file, "%s/%s", save_path, file.ff_name);
- unlink(nntp_file);
- expired++;
- }
- }
- }
- if(expired)
- log(-1,"NNTP Expired: %d in %s",expired, nntp_name);
- }
- #endif /*nntps*/
-
- void
- expire(filename,age)
- char *filename;
- int age;
- {
- int oldidx,idx,expired,i;
- FILE *old,*new;
- long start,pos,msgsize;
- time_t now;
- struct indexhdr hdr;
- struct mailindex index;
- char file[FILE_PATH_SIZE];
- char bckfile[FILE_PATH_SIZE];
- char buf[LINELEN];
-
- dirformat(filename);
-
- if(mlock(Mailspool,filename))
- /* can't get a lock */
- return;
-
- /* Rename the index file, and use it to expire messages */
- sprintf(file,"%s/%s.ind",Mailspool,filename);
- sprintf(bckfile,"%s/%s.idn",Mailspool,filename);
- unlink(bckfile);
- if(rename(file,bckfile) == -1) {
- rmlock(Mailspool,filename);
- return;
- }
- /* Open the old index file */
- if((oldidx=open(bckfile,READBINARY)) == -1) {
- rmlock(Mailspool,filename);
- return;
- }
- /* Create the new index file */
- if((idx=open(file,CREATETRUNCATEBINARY,CREATEMODE)) == -1) {
- close(oldidx);
- rmlock(Mailspool,filename);
- return;
- }
-
- /* Rename the text file */
- sprintf(file,"%s/%s.txt",Mailspool,filename);
- /* get the name for the backup file */
- sprintf(bckfile,"%s/%s.bak",Mailspool,filename);
-
- /* rename the file */
- unlink(bckfile);
- if(rename(file,bckfile) == -1) {
- close(oldidx);
- close(idx);
- rmlock(Mailspool,filename);
- return;
- }
- /* open the backup file and the new txt file */
- if((old=fopen(bckfile,"rb")) == NULL) {
- close(oldidx);
- close(idx);
- rmlock(Mailspool, filename);
- return;
- }
- if((new=fopen(file,"wt")) == NULL) {
- close(oldidx);
- close(idx);
- fclose(old);
- rmlock(Mailspool, filename);
- return;
- }
-
- /* Write a default header to the new index file */
- default_header(&hdr);
- write_header(idx,&hdr);
-
- memset(&index,0,sizeof(index));
- time(&now);
- start = pos = 0;
- expired = 0;
-
- /* Read the header from the old index file */
- read_header(oldidx,&hdr);
-
- /* Now read all messages, and expire old ones */
- for(i = 0; i < hdr.msgs; i++) {
- default_index(filename,&index);
- read_index(oldidx,&index);
- msgsize = index.size;
- if(now - index.date < (age*86400L)) {
- /* This one we should keep ! Copy it from old to new */
- fseek(old,start,SEEK_SET);
- pos = ftell(new);
- /* Read the first line, should be 'From ' line */
- bgets(buf,sizeof(buf),old);
- fprintf(new,"%s\n",buf);
- /* Now do the rest until we find another 'From ' or
- * reach end of file.
- */
- while(bgets(buf,sizeof(buf),old) != NULL) {
- pwait(NULL);
- if(!strncmp(buf,"From ",5))
- break;
- fprintf(new,"%s\n",buf);
- }
- /* rewrite the index file for the message */
- index.size = ftell(new) - pos;
- WriteIndex(idx,&index);
- } else
- expired++;
- start += msgsize; /* starting offset of the next message */
- }
- default_index("",&index);
- close(oldidx);
- close(idx);
- fclose(new);
- fclose(old);
- rmlock(Mailspool,filename);
- if(expired)
- log(-1,"Expired: %d in %s",expired,filename);
- }
-
-
- /******************************************************************/
- /* This program will deleted old BID's from the history file,
- * after making a backup copy.
- *
- * Eg. 'oldbids 24 30' will try to delete all bids older then 30 days
- * every 24 hours.
- * 'oldbids now' will do it now, with set value of age.
- *
- * Copyright 1992, Johan. K. Reinalda, WG7J/PA3DIS
- * email : johan@ece.orst.edu
- * packet: wg7j@wg7j.or.usa.na
- *
- * Any part of this source may be freely distributed for none-commercial,
- * amateur radio use only, as long as credit is given to the author.
- *
- * v1.0 920325
- */
- static struct timer Oldbidtimer;
- static int Oldbid_age = 30;
-
- static
- void
- Oldbidtick(p)
- void *p;
- {
- int expired = 0;
- char *cp;
- FILE *old, *new;
- time_t now;
- time_t age;
- time_t bidtime;
- #define LEN 80
- char oldfile[LEN];
- char buf[LEN];
-
- stop_timer(&Oldbidtimer);
-
- /* delete a previous backup and rename current history file */
- sprintf(oldfile,"%s.bak",Historyfile);
- unlink(oldfile);
- if(rename(Historyfile,oldfile) == -1) {
- tputs("oldbid: can't rename history file\n");
- return;
- }
-
- /* open backup for reading, create new history file */
- if((old = fopen(oldfile,"rt")) == NULL) {
- tputs("oldbid: error opening history.bak\n");
- return;
- }
- if((new = fopen(Historyfile,"wt")) == NULL) {
- tputs("oldbid: error creating history file\n");
- return;
- }
-
- now = time(&now);
- age = (time_t)(Oldbid_age*86400L);
-
- while(fgets(buf,LEN,old) != NULL) {
- if((cp=strchr(buf,'\n')) != NULLCHAR)
- *cp = '\0';
- if((cp=strchr(buf,' ')) != NULLCHAR) {
- /*found one with timestamp*/
- *cp = '\0';
- cp++; /* now points to timestamp */
- if((bidtime = atol(cp)) == 0L)
- /*something wrong, re-stamp */
- fprintf(new,"%s %ld\n",buf,now);
- else {
- /* Has this one expired yet ? */
- if(now - bidtime < age)
- fprintf(new,"%s %ld\n",buf,bidtime);
- else
- expired++;
- }
- } else {
- /* This is an old one without time stamp,
- * add to the new file with current time as timestamp
- */
- fprintf(new,"%s %ld\n",buf,now);
- }
- }
- fclose(old);
- fclose(new);
- if(expired)
- log(-1,"Oldbids: %d expired",expired);
- start_timer(&Oldbidtimer);
- return;
- }
-
- int
- dooldbids(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- if(argc < 2){
- tprintf("timer: %lu/%lu hrs; age: %d days\n",
- read_timer(&Oldbidtimer)/MSPHOUR,
- dur_timer(&Oldbidtimer)/MSPHOUR,
- Oldbid_age);
- return 0;
- }
- if(*argv[1] == 'n') {
- Oldbidtick(NULL);
- return 0;
- }
- /* set the timer */
- stop_timer(&Oldbidtimer); /* Just in case */
- Oldbidtimer.func = (void (*)())Oldbidtick;/* what to call on timeout */
- Oldbidtimer.arg = NULL; /* dummy value */
- set_timer(&Oldbidtimer,atol(argv[1])*MSPHOUR); /* set timer duration */
- if(argc > 2)
- Oldbid_age = atoi(argv[2]);
- Oldbidtick(NULL); /* Do one now and start it all!*/
- return 0;
- }
-
- #endif /* EXPIRE */
-